package com.wei.czz.framework.security.filter;

import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.admin.user.RequestChannelEnum;
import com.wei.czz.common.enums.common.multiDIct.MultiDictEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.admin.accessToken.UserAccessTokenPo;
import com.wei.czz.common.tool.Result;
import com.wei.czz.common.utils.ContextUtils;
import com.wei.czz.common.utils.HttpUtils;
import com.wei.czz.framework.admin.entity.UserRiskFlowEntity;
import com.wei.czz.framework.admin.helper.UserHelper;
import com.wei.czz.framework.admin.service.UserRiskFlowService;
import com.wei.czz.framework.common.entity.MultiDictEntity;
import com.wei.czz.framework.common.helper.MultiDictHelper;
import com.wei.czz.framework.common.service.AesService;
import com.wei.czz.framework.security.entity.SecurityUser;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2025-04-29 10:56:50
 * className: RefreshTokenFilter
 * version: 1.0
 * description:
 */
@Order(2)
@Component
@AllArgsConstructor
public class RefreshTokenFilter extends OncePerRequestFilter {

    private static final Logger log = LoggerFactory.getLogger(RefreshTokenFilter.class);

    private final UserRiskFlowService userRiskFlowService;

    private final AesService aesService;

    private final UserHelper userHelper;

    private final MultiDictHelper multiDictHelper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
//        log.info("进入RefreshTokenFilter requestUri={} method={}", request.getRequestURI(), request.getMethod());

        // 从上下文参数中获取访问令牌、刷新令牌、请求渠道
        String accessToken = ContextUtils.get(Constant.ACCESS_TOKEN);
        String refreshToken = ContextUtils.get(Constant.REFRESH_TOKEN);
        String requestChannel = ContextUtils.get(Constant.REQUEST_CHANNEL);

        try {
            // 获取web服务器ip地址
            String serverIp = request.getRemoteAddr();

            // 如果访问令牌为空，则直接放行请求
            if (StringUtils.isNotBlank(accessToken)) {
                // 请求继续往下走
                filterChain.doFilter(request, response);
                return;
            }

            // 如果刷新令牌为空，则直接放行请求
            if (StringUtils.isBlank(refreshToken)) {
                // 请求继续往下走
                filterChain.doFilter(request, response);
                return;
            }

            /*
                获取web服务ip字典列表
             */
            List<MultiDictEntity> multiDictList = multiDictHelper.getList(MultiDictEnum.WEB_SERVER_IP);
            boolean bool = multiDictList.stream()
                    .noneMatch(multiDict -> multiDict.getValue().equals(serverIp));
            log.info("判断请求ip是否为web服务ip完成。bool={}", bool);
            if (bool) {
                // 请求继续往下走
                filterChain.doFilter(request, response);
                return;
            }

            long now = System.currentTimeMillis();

            /*
                访问令牌解密
             */
            String _userId = aesService.czzDecrypt(refreshToken);
            log.info("访问令牌解密得到用户主键：{}", _userId);
            long userId;
            try {
                userId = Long.parseLong(_userId);
            } catch (NumberFormatException e) {
                log.warn("访问令牌携带的不是用户主键。_userId={}", _userId);
                throw new CzzException(ResultEnum.TOKEN_INVALID);
            }
            // 将用户主键放到上下文参数中
            ContextUtils.set(Constant.USER_ID, userId);

            // 获取请求渠道枚举对象
            RequestChannelEnum requestChannelEnum = RequestChannelEnum.get(requestChannel);
            if (Objects.isNull(requestChannelEnum)) {
                log.info("请求渠道未知。userId={} requestChannel={}", userId, requestChannel);
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "请求渠道未知");
            }

            /*
                获取请求登录用户
             */
            SecurityUser securityUser = userHelper.getSecurityUser(userId, requestChannelEnum);

            /*
                用户令牌校验
             */
            UserAccessTokenPo userAccessToken = securityUser.getAccessToken();
            if (Objects.isNull(userAccessToken)) {
                log.info("用户令牌不存在。userId={} requestChannel={}", userId, requestChannel);
                throw new CzzException(ResultEnum.TOKEN_EXPIRE.getCode(), "登录已过期，请重新登陆后再操作");
            }
            bool = Optional.of(userAccessToken)
                    .filter(accessTokenPo -> accessTokenPo.getChannel().equals(requestChannelEnum.getValue()))
                    .filter(accessTokenPo -> accessTokenPo.getRefreshExpireTime() > now)
                    .filter(accessTokenPo -> accessTokenPo.getRefreshToken().equals(refreshToken))
                    .isEmpty();
            if (bool) {
                // 获取用户令牌列表
                List<UserAccessTokenPo> accessTokenList = securityUser.getAccessTokenList();

                // 判断令牌是否与用户关联的令牌有相同
                bool = accessTokenList.stream()
                        .filter(accessTokenPo -> accessTokenPo.getChannel().equals(requestChannelEnum.getValue()))
                        .filter(accessTokenPo -> accessTokenPo.getRefreshExpireTime() > now)
                        .noneMatch(accessTokenPo -> accessTokenPo.getRefreshToken().equals(refreshToken));
                if (bool) {
                    log.info("用户令牌不存在。userId={} requestChannel={}", userId, requestChannel);
                    // 旧令牌机制，提示用户
                    throw new CzzException(ResultEnum.TOKEN_EXPIRE.getCode(), "登录已过期，请重新登陆后再操作");
                }
            }

            /*
                用户状态校验
             */
            if (!securityUser.isAccountNonLocked()) {
                // 获取用户风控信息
                UserRiskFlowEntity userRisk = userRiskFlowService.findLastUserRiskFlow(userId);
                if (Objects.isNull(userRisk)) {
                    log.error("用户已被禁用，但是没有风控信息，请务必及时处理");
                    throw new CzzException();
                }

                Result<String> result = Result.getResult(ResultEnum.DISABLE_USER);
                result.setData(userRisk.getId().toString());

                // 直接返回结果
                HttpUtils.setResponse(request, response, result);
                return;
            }
            log.info("请求用户名称：{}", securityUser.getUsername());

            // 将用户信息存入ThreadLocal中，后面的逻辑可以获取存入的值
            ContextUtils.set(Constant.SECURITY_USER, securityUser);

            // 请求继续往下走
            filterChain.doFilter(request, response);

        } catch (CzzException czzException) {
            HttpUtils.setResponse(request, response, czzException.getCode(), czzException.getMessage());
        } catch (Exception e) {
            log.error("用户权限校验发生异常。message={}", e.getMessage(), e);
            HttpUtils.setResponse(request, response, ResultEnum.SERVICE_FAIL.getCode(), ResultEnum.SERVICE_FAIL.getMsg());
        }


    }
}
